
#include<stdio.h>
#include <string.h>

#include "SEGGER_RTT.h"
#include "FreeRTOS.h"
#include "task.h"


#include "drv_bc26.h"
#include "misc.h"
#include "base16.h"
#include "base64.h"
#include "encoding.h"
#include "nrf_error.h"



void drv_bc26_connect_ok(uint8_t *pdata, uint32_t len) {
    MSG_AT msg_at;
    msg_at.info = AT_INFO_CONNECT_OK;
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("fail to pass the info");
    }
}

void drv_bc26_update_ok(uint8_t *pdata, uint32_t len) {
    MSG_AT msg_at;
    msg_at.info = AT_INFO_UPDATE_OK;
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("fail to pass the info");
    }
}

void drv_bc26_close_ok(uint8_t *pdata, uint32_t len) {
    MSG_AT msg_at;
    msg_at.info = AT_INFO_CLOSE_OK;
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("fail to pass the info");
    }
}
void drv_bc26_version(uint8_t *pdata, uint32_t len) {
    char *pstr;
    uint32_t str_len;
//    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_str(&pdata, &len, &pstr, &str_len)) {
        return;
    }
    memcpy(env_net.nb_version, pstr, str_len);
    env_net.nb_version[str_len] = '\0';
}
void drv_bc26_qlwobserve(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number == 0) {
        msg_at.info = AT_INFO_LWOBSERVE_REQUEST;
        if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
            NET_ERR("fail to pass the info");
        }
    } else if (number == 1) {
        msg_at.info = AT_INFO_LWOBSERVE_CANCEL;
        if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
            NET_ERR("fail to pass the info");
        }
    } else {
        NET_ERR("");
    }
}
extern app_fifo_t fifo_upgrade;
//#include "common_interfaces.h"
//+QLWDATARECV: 19,1,0,4,AAAA0000
void drv_bc26_qlwdatarecv(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_RECV msg_recv;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number != 19) {
        NET_ERR("invalid object id");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number != 1) {
        NET_ERR("invalid instace id");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number != 0) {
        NET_ERR("invalid source id");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number > 512) {
        NET_ERR("invalid data length");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
	if(pdata[0] != '0' && pdata[1] != '1') {
		len = base16_decode(pdata,len,pdata,len);
		if(len == 0) {
			return;
		}
		NET_INF("decode len=%d",len);
		app_fifo_write(&fifo_upgrade, pdata, &len);
		msg_recv.type = MSG_RECV_UPGRADE;
	}  else {
		len = base64_base16_decode(pdata + 6, len - 6, pdata, len - 6);
		if (len == 0) {
			NET_ERR("failed to decode by base64_base16");
			return;
		}
		app_fifo_write(&(env_net.pconns[0].fifo), pdata, &len);
		msg_recv.type = MSG_RECV_SOCKET;
	}
    msg_recv.value = 0;
    if (xQueueSend(env_net.qrecv, &msg_recv, 200) != pdPASS) {
        NET_ERR("failed to pass recv");
    }
}
void drv_bc26_cgsn(uint8_t *pdata, uint32_t len) {
    char *pstr;
    uint32_t str_len;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_str(&pdata, &len, &pstr, &str_len)) {
        return;
    }
    if (str_len >= sizeof(env_net.pimei)) {
        NET_INF("invalid imei:%s", pdata);
        return;
    }
    memcpy(env_net.pimei, pstr, str_len);
    env_net.pimei[str_len] = '\0';
    NET_INF("imei:%s", env_net.pimei);
}
void drv_bc26_cimi(uint8_t *pdata, uint32_t len) {
    memcpy(env_net.pimsi, pdata, len);
    env_net.pimsi[len] = '\0';
    NET_INF("imsi:%s", env_net.pimsi);
}
void drv_bc26_qccid(uint8_t *pdata, uint32_t len) {
    memcpy(env_net.qccid, pdata, len);
    env_net.pimsi[len] = '\0';
    NET_INF("qccid:%s", env_net.qccid);
}
void drv_bc26_ip(uint8_t *pdata, uint32_t len) {
    char *pstr;
    uint32_t str_len;
//    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_str(&pdata, &len, &pstr, &str_len)) {
        return;
    }
    memcpy(env_net.pip, pstr, str_len);
    env_net.pip[str_len] = '\0';
    NET_INF("ip:%s", env_net.pip);

//    env_net.state = NET_STATE_IP_READY;
//    msg_at.info = AT_INFO_IP;
//    if(xQueueSend(env_net.qinfo,&msg_at,200) != pdPASS){
//        NET_ERR("fail to pass the info");
//    }
}
void drv_bc26_cpin(uint8_t *pdata, uint32_t len) {
    char *pstr;
    uint32_t str_len;
    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_str(&pdata, &len, &pstr, &str_len)) {
        return;
    }
    if (!str_cmp(pstr, str_len, CSTRING("READY"))) {
        msg_at.info = AT_INFO_CARD_READY;
    } else {
        msg_at.info = AT_INFO_CARD_ERR;
    }
    pstr[str_len] = '\0';
    NET_DBG("card is %s", pstr);
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("failed to pass the info");
    }
}

void drv_bc26_cgatt(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if ((number == 0) || (number == 1)) {
        if (number == 0) {
            msg_at.info = AT_INFO_CGATT0;
        } else {
            msg_at.info = AT_INFO_CGATT1;
        }
        if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
            NET_ERR("fail to pass the info");
        }
    } else {
        NET_ERR("invalid info");
    }
}
void drv_bc26_cgpaddr(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    char *pstr;
    uint32_t str_len;
    MSG_AT msg_at;

    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    env_net.cid = number;
    NET_INF("cgpaddr cid:%d", env_net.cid);
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_str(&pdata, &len, &pstr, &str_len)) {
        return;
    }
    memcpy(env_net.pip, pstr, str_len);
    env_net.pip[str_len] = '\0';
    NET_INF("cgpaddr ip:%s", env_net.pip);

//    env_net.state = NET_STATE_IP_READY;
    msg_at.info = AT_INFO_CGPADDR;
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("fail to pass the info");
    }
}
//+CSCON: <n>,<mode>[,<state>]
void drv_bc26_cscon(uint8_t *pdata, uint32_t len) {
    BYTES bytes = { .pdata = pdata, .len = len };
    uint32_t mode;
    MSG_AT msg_at;
    if (at_match(&bytes, "+u,+u", NULL, &mode)) {
        return;
    }
    msg_at.info = AT_INFO_CSCON;
    msg_at.value = mode;
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("fail to pass the info");
    }
}

void drv_bc26_cgdcont(uint8_t *pdata, uint32_t len) {
    BYTES bytes = { .pdata = pdata, .len = len };
    BYTES apn;
    if (at_match(&bytes, "+u,+s,+s", NULL, NULL, &apn)) {
        return;
    }
    apn.pdata[apn.len] = '\0';
    NET_INF("apn:%s", apn.pdata);
    if (strcasecmp((const char *)apn.pdata, "cmnbiot") == 0) {
        env_net.carrier = DRV_NET_CARRIER_CM;
    } else if (strcasecmp((const char *)apn.pdata, "ctnb") == 0) {
        env_net.carrier = DRV_NET_CARRIER_CT;
    } else { //not support now
        env_net.carrier = DRV_NET_CARRIER_MAX;
    }
    NET_INF("carrier is %d", env_net.carrier);
}
void drv_bc26_csq(uint8_t *pdata, uint32_t len) {
    BYTES bytes = { .pdata = pdata, .len = len };
    uint32_t sq;
    if (at_match(&bytes, "+u", &sq)) {
        return;
    }
    env_net.sq = sq;
}
void drv_bc26_miplcreate(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number == 0) {
        msg_at.info = AT_INFO_CSI_OK;
    } else {
        msg_at.info = AT_INFO_CSI_ERROR;
    }
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("fail to pass the info");
    }
}
void drv_bc26_miplevent(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number != 0) {
        NET_ERR("invalid csi %d", number);
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (BETWEEN11(6, number, 8)) {
        if (number == 6) {
            NET_INF("registered the onenet platform successfully");
            msg_at.info = AT_INFO_REG_SUCCESS;
        } else if (number == 7) {
            NET_INF("failed to register the onenet platform");
            msg_at.info = AT_INFO_REG_FAILED;
        } else {
            NET_INF("registered the onenet platform timeout");
            msg_at.info = AT_INFO_REG_TIMEOUT;
        }
        if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
            NET_ERR("fail to pass the info");
        }
    } else if (number == 1) {
        NET_INF("start to connect to bootstrap server");
    } else if (number == 2) {
        NET_INF("connect to bootstrap server successfully");
    } else if (number == 4) {
        NET_INF("connect to onenet platform successfully");
    } else if (number == 15) {
        NET_INF("deregistered the onenet platform successfully");
        msg_at.info = AT_INFO_DEREG_DONE;
        if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
            NET_ERR("fail to pass the info");
        }
    }
}

//+MIPLOBSERVE:  <ref>,<msgId>,<flag>,<objId>,<insId>,<resId>
void drv_bc26_miplobserve(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_RECV msg_recv;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //<ref>
        return;
    }
    if (number != 0) {
        NET_ERR("invalid csi");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //<msgId>
        return;
    }
    msg_recv.type = MSG_RECV_OBSERVE;
    msg_recv.value = number; //packet id

    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //<flag>
        return;
    }
    if (number != 1) {
        NET_WAR("cancel observe");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //<objId>
        return;
    }
    if (number != CM_OBJ_ID) {
        NET_ERR("invalid object id");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //<insId>
        return;
    }
    if (number == 0) {
        env_net.cm_up_msg_id = msg_recv.value;
    } else if (number == 1) {
        env_net.cm_down_msg_id = msg_recv.value;
    } else {
        NET_ERR("invalid instance %d", number);
        return;
    }
    //do something
    if (xQueueSend(env_net.qrecv, &msg_recv, 200) != pdPASS) {
        NET_ERR("failed to pass the observe message");
        return;
    }
}
//+MIPLDISCOVER:  <ref>,<msgId>,<objId>
//example:+MIPLDISCOVER: 0,25995,3348
void drv_bc26_mipldiscover(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_RECV msg_recv;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number != 0) {
        NET_ERR("invalid csi");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    msg_recv.type = MSG_RECV_DISCOVER;
    msg_recv.value = number; //packet id
    if (xQueueSend(env_net.qrecv, &msg_recv, 200) != pdPASS) {
        NET_ERR("failed to pass the discover message");
        return;
    }
}
//+MIPLWRITE:  <ref>,<msgId>,<objId>,<insId>,<resId>,<valueType>,<len>[,<value>],<flag>,<index>
//+MIPLWRITE: 0,38017,3348,0,5750,2,5,68656C6C6F,0,0
//+MIPLWRITE: 0,41029,3348,1,5750,2,4,4D544578,0,0
#if 1
void drv_bc26_miplwrite(uint8_t *pdata, uint32_t len) {
    BYTES bytes = { .pdata = pdata, .len = len };
    uint32_t mid;
    int32_t csi;
    int32_t obj_id, inst_id, res_id;
    MSG_RECV msg_recv;
    uint32_t data_type, data_len;
    if (at_match(&bytes, "+d,+u,+d,+d,+d,", &csi, &mid, &obj_id, &inst_id, &res_id)) {
        NET_ERR("failed to match");
        return;
    }
    if ((csi != 0) ||
        (obj_id != CM_OBJ_ID) ||
        (inst_id != CM_INS_ID_DOWN) ||
        (res_id != CM_RES_ID)) {
        pdata[len] = '\0';
        NET_ERR("invalid write:%s", pdata);
        return;
    }
    if (at_match(&bytes, "+u,+u,", &data_type, &data_len)) {
        return;
    }
    if (data_type != 2) {
        NET_INF("not support data type %d", data_type);
        return;
    }
    data_len = base16_decode(bytes.pdata, data_len << 1, bytes.pdata, data_len);
    if (data_len == 0) {
        NET_ERR("failed to decode by base16");
        return;
    }
    data_len = base64_decode(bytes.pdata, data_len, bytes.pdata, data_len);
    if (data_len == 0) {
        NET_ERR("failed to decode by base64");
        return;
    }
    msg_recv.type = MSG_RECV_WRITE;
    msg_recv.value = mid;
    if (xQueueSend(env_net.qrecv, &msg_recv, 200) != pdPASS) {
        NET_WAR("failed to pass the write msg");
    }
    app_fifo_write(&(env_net.pconns[0].fifo), bytes.pdata, &data_len);
    msg_recv.type = MSG_RECV_SOCKET;
    msg_recv.value = 0;
    if (xQueueSend(env_net.qrecv, &msg_recv, 200) != pdPASS) {
        NET_WAR("failed to pass the socket msg");
    }
}
#else
void drv_bc26_miplwrite(uint8_t *pdata,uint32_t len){
    uint32_t number;
    MSG_RECV msg_recv;

    if(data_skip(&pdata,&len,':')){
        return;
    }
    if(data_to_num(&pdata,&len,&number)){ //ref
        return;
    }
    if(number != 0){
        NET_ERR("invalid csi");
        return;
    }
    if(data_skip(&pdata,&len,',')){
        return;
    }
    if(data_to_num(&pdata,&len,&number)){ //
        return;
    }
    msg_recv.type = MSG_RECV_WRITE;
    msg_recv.value = number;
    if(xQueueSend(env_net.qrecv,&msg_recv,200) != pdPASS){
        NET_ERR("failed to pass the write message");
        return;
    }

    if(data_skip(&pdata,&len,',')){
        return;
    }
    pdata[len] = '\0';
    NET_INF("write %s",pdata);
}
#endif

void drv_bc26_miplread(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_RECV msg_recv;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number != 0) {
        NET_ERR("invalid csi");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    msg_recv.type = MSG_RECV_READ;
    msg_recv.value = number;
    if (xQueueSend(env_net.qrecv, &msg_recv, 200)) {
        NET_ERR("failed to pass the write message");
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    pdata[len] = '\0';
    NET_INF("read %s", pdata);
}
/*
****************************************************************************************************
tcp/udp
****************************************************************************************************
*/
//+QIOPEN: <connectID>,<err>
void drv_bc26_qiopen(uint8_t *pdata, uint32_t len) {
    uint32_t number;
    MSG_AT msg_at;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //get socket
        return;
    }
    msg_at.value = number;
    if (number >= DRV_NET_MAX_NUM_OF_CONNECTIONS) {
        NET_ERR("invalid socket %d", number);
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) {
        return;
    }
    if (number == 0) {
        msg_at.info = AT_INFO_SOCKET_OPEN_OK;
    } else {
        msg_at.info = AT_INFO_SOCKET_OPEN_ERROR;
    }
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("failed to pass info");
        return;
    }
}

void drv_bc26_send_ok(uint8_t *pdata, uint32_t len) {
    MSG_AT msg_at;
    msg_at.info = AT_INFO_SOCKET_SEND_OK;
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("failed to pass info");
        return;
    }
}
void drv_bc26_send_fail(uint8_t *pdata, uint32_t len) {
    MSG_AT msg_at;
    msg_at.info = AT_INFO_SOCKET_SEND_FAIL;
    if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("failed to pass info");
        return;
    }
}

void drv_bc26_qeng(uint8_t *pdata,uint32_t len) {
    BYTES bytes = { .pdata = pdata, .len = len };
    uint32_t mode;
    if (at_match(&bytes, "+u,", &mode, NULL)) {
        return;
    }
    if (mode != 0) {
        return;//do nothing
    }
    uint32_t pci;
    BYTES cell_id;
    if (at_match(&bytes,"+u,+u,+u,+s",NULL,NULL,&pci,&cell_id)) {
        return;
    }
    env_net.cell_inf.pci = pci;
    cell_id.pdata[cell_id.len] = '\0';
    strncpy((char *)env_net.cell_inf.cell_id, (char *)cell_id.pdata, 8);
}

void bsp_bc26_qiurc(uint8_t *pdata, uint32_t len) {
    char *pstr;
    uint32_t str_len;
    uint32_t number;
    NET_CONNECTION *pconn;
    MSG_RECV msg_recv;
    if (data_skip(&pdata, &len, ':')) {
        return;
    }
    if (data_to_dqstr(&pdata, &len, &pstr, &str_len)) {
        return;
    }
    if (!str_cmp(pstr, str_len, CSTRING("recv"))) { //receive?
    } else if (!str_cmp(pstr, str_len, CSTRING("closed"))) { //close?
        if (data_skip(&pdata, &len, ',')) {
            return;
        }
        if (data_to_num(&pdata, &len, &number)) {
            return;
        }
        if (number < DRV_NET_MAX_NUM_OF_CONNECTIONS) {
            //do something
            NET_INF("close socket %d", number);
        }
        return;
    } else { //others
        pstr[str_len] = '\0';
        NET_WAR("invalid type %s", pstr);
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //get socket
        return;
    }
    if (number >= DRV_NET_MAX_NUM_OF_CONNECTIONS) { //is socket valid?
        NET_ERR("invalid socket %d", number);
        return;
    }
    pconn = &(env_net.pconns[number]);
    msg_recv.type = MSG_RECV_SOCKET;
    msg_recv.value = number;
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if (data_to_num(&pdata, &len, &number)) { //get length
        return;
    }
    if (data_skip(&pdata, &len, ',')) {
        return;
    }
    if ((number << 1) !=  len) { //is length valid
        NET_ERR("length doesn't match,%d,%d", number, len);
        return;
    }
    hstr_to_bin(pdata, pdata, number);
    app_fifo_write(&(pconn->fifo), pdata, &number);
    if (xQueueSend(env_net.qrecv, &msg_recv, 200) != pdPASS) {
        NET_ERR("failed to pass recv");
    }
}

extern void recv_upgrade_handler(uint8_t data);
void drv_bc26_recv_excute(MSG_RECV *pmsg_recv) {
    char pbuf[64];
    int32_t len;
    NET_ERR_CODE ret;
    MSG_AT msg_at;
    DRV_NET_RECV_HANDLER recv_handler;
    NET_CONNECTION *pconn;
    uint8_t data;
    if (pmsg_recv->type == MSG_RECV_OBSERVE) {
        //AT+MIPLOBSERVERSP=<ref>,<msgId>,<result>
        //AT+MIPLOBSERVERSP=0,69234,1
        len = snprintf(pbuf, sizeof(pbuf), "AT+MIPLOBSERVERSP=0,%d,1\r", pmsg_recv->value);
        if (len < 0) {
            NET_ERR("failed to format");
            return;
        }
        ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
        if (ret < 0) {
            NET_ERR("");
            return;
        }
    } else if (pmsg_recv->type == MSG_RECV_DISCOVER) {
        //AT+MIPLDISCOVERRSP=<ref>,<msgid>,<result>,<length>,<valuestring>
        //AT+MIPLDISCOVERRSP=0,26384,1,4,"5750"
        len = snprintf(pbuf, sizeof(pbuf), "AT+MIPLDISCOVERRSP=0,%d,1,%d,\"%s\"\r", pmsg_recv->value, sizeof(CM_RES_ID_STR) - 1, CM_RES_ID_STR);
        if (len < 0) {
            NET_ERR("failed to format");
            return;
        }
        ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
        if (ret < 0) {
            NET_ERR("");
            msg_at.info = AT_INFO_MIPLDISCOVER_ERROR;
        } else {
            msg_at.info = AT_INFO_MIPLDISCOVER_OK;
        }
        if (xQueueSend(env_net.qinfo, &msg_at, 200) != pdPASS) {
            NET_ERR("failed to pass info");
        }
    } else if (pmsg_recv->type == MSG_RECV_WRITE) {
        //AT+MIPLWRITERSP=<ref>,<msgId>,<result>
        //AT+MIPLWRITERSP=0,38017,2
        len = snprintf(pbuf, sizeof(pbuf), "AT+MIPLWRITERSP=0,%d,2\r", pmsg_recv->value);
        if (len < 0) {
            NET_ERR("failed to format");
            return;
        }
        ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
        if (ret < 0) {
            NET_ERR("");
        }
    } else if (pmsg_recv->type == MSG_RECV_READ) {
        //todo:onenet read
        NET_WAR("not surpport");
    } else if (pmsg_recv->type == MSG_RECV_SOCKET) {
        if (pmsg_recv->value >= DRV_NET_MAX_NUM_OF_CONNECTIONS) {
            NET_ERR("invalid socket %d", pmsg_recv->value);
            return;
        }
        pconn = &(env_net.pconns[pmsg_recv->value]);
        recv_handler = pconn->handler;
        if (recv_handler == NULL) {
            return;
        }
        while (app_fifo_get(&(pconn->fifo), &data) == FIFO_SUCCESS) {
            recv_handler(data);
        }
    } else if(pmsg_recv->type == MSG_RECV_UPGRADE) {
		while (app_fifo_get(&fifo_upgrade, &data) == FIFO_SUCCESS) {
            recv_upgrade_handler(data);
        }
    } else {
        NET_ERR("invalid msg type%d", pmsg_recv->type);
    }
}

int32_t drv_bc26_any(uint8_t *pdata, uint32_t len) {
    if (!str_all_number_pre((const char *)pdata, len)) {
        pdata[len] = '\0';
        if (len >= sizeof(env_net.pimsi)) {
            NET_INF("invalid imsi:%s", pdata);
            return -1;
        }
        strcpy(env_net.pimsi, (const char *)pdata);
        NET_INF("imsi:%s", env_net.pimsi);
        return 0;
    }
    return -1;
}

void drv_bc26_cclk(uint8_t *pdata, uint32_t len)
{
	NET_DATE_T t;
	BYTES bytes = { .pdata = pdata, .len = len };
	if (at_match(&bytes, "+u/+u/+u,+u:+u:+u",&t.year,&t.month,&t.days,&t.hours,&t.min,&t.sec)) {
		return;
	}
	NET_INF("date : %d/%d/%d : %d/%d/%d", t.year,t.month,t.days,t.hours,t.min,t.sec);
	memcpy(&env_net.date_t, &t,sizeof(NET_DATE_T));
}

AT_HANDLER drv_bc26_at_handlers[] = {
    AT_HANDLER_GENERAL_DEF("OK", drv_net_result_ok),
    AT_HANDLER_GENERAL_DEF("ERROR", drv_net_result_error),
    AT_HANDLER_GENERAL_DEF("CONNECT OK", drv_bc26_connect_ok),
    AT_HANDLER_GENERAL_DEF("UPDATE OK", drv_bc26_update_ok),
    AT_HANDLER_GENERAL_DEF("CLOSE OK", drv_bc26_close_ok),
	AT_HANDLER_GENERAL_DEF("Revision", drv_bc26_version),
    AT_HANDLER_GENERAL_DEF("+QLWOBSERVE", drv_bc26_qlwobserve),
    AT_HANDLER_GENERAL_DEF("+QLWDATARECV", drv_bc26_qlwdatarecv),
    AT_HANDLER_GENERAL_DEF("+CGSN", drv_bc26_cgsn),
    AT_HANDLER_GENERAL_DEF("+IP", drv_bc26_ip),
    AT_HANDLER_GENERAL_DEF("+CPIN", drv_bc26_cpin),
    AT_HANDLER_GENERAL_DEF("+CGATT", drv_bc26_cgatt),
    AT_HANDLER_GENERAL_DEF("+CGPADDR", drv_bc26_cgpaddr),
    AT_HANDLER_GENERAL_DEF("+CSCON:", drv_bc26_cscon),
    AT_HANDLER_GENERAL_DEF("+CGDCONT:", drv_bc26_cgdcont),
    AT_HANDLER_GENERAL_DEF("+CSQ:", drv_bc26_csq),
    AT_HANDLER_GENERAL_DEF("+QENG:",drv_bc26_qeng),
	AT_HANDLER_GENERAL_DEF("+CCLK:",drv_bc26_cclk),
	AT_HANDLER_GENERAL_DEF("+QCCID:",drv_bc26_qccid),
    /** onenet */
    AT_HANDLER_GENERAL_DEF("+MIPLCREATE", drv_bc26_miplcreate),
    AT_HANDLER_GENERAL_DEF("+MIPLEVENT", drv_bc26_miplevent),
    AT_HANDLER_GENERAL_DEF("+MIPLOBSERVE", drv_bc26_miplobserve),
    AT_HANDLER_GENERAL_DEF("+MIPLDISCOVER", drv_bc26_mipldiscover),
    AT_HANDLER_GENERAL_DEF("+MIPLWRITE:", drv_bc26_miplwrite),
    AT_HANDLER_GENERAL_DEF("+MIPLREAD", drv_bc26_miplread),
    /** tcp/udp */
    AT_HANDLER_GENERAL_DEF("+QIURC", bsp_bc26_qiurc),
    AT_HANDLER_GENERAL_DEF("+QIOPEN", drv_bc26_qiopen),
    AT_HANDLER_GENERAL_DEF("SEND OK", drv_bc26_send_ok),
    AT_HANDLER_GENERAL_DEF("SEND FAIL", drv_bc26_send_fail),
    AT_HANDLER_ANY(drv_bc26_any)
};




//China Telecom connect,use imei
NET_ERR_CODE drv_bc26_ct_connect(char *pstr_ip, char *pstr_port, uint32_t fifo_size) {
    char pbuf[64];
    int32_t len;
    NET_ERR_CODE ret;
    MSG_AT msg_at;

    ret = drv_net_fifo_init(&(env_net.pconns[0].fifo), fifo_size);
    if (ret < 0) {
        return ret;
    }

    //AT+QLWDEL\r
    drv_net_write_bytes_raw(5000,1,TSTRING(uint8_t *,"AT+QLWDEL\r")); //ignore the error code

    //AT+QLWSERV="180.101.147.115",5683\r
    len = snprintf(pbuf, sizeof(pbuf), "AT+QLWSERV=\"%s\",%s\r", pstr_ip, pstr_port);
    if (len < 0) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    ret = drv_net_write_bytes_raw(400, 1, (uint8_t *)pbuf, len);
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    //AT+QLWCONF="866971030393149"\r
    if (strlen(env_net.pimei) == 0) {
        NET_ERR("no imei");
        return NET_ERR_UNKOWN;
    }
    len = snprintf(pbuf, sizeof(pbuf), "AT+QLWCONF=\"%s\"\r", env_net.pimei);
    if (len < 0) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    //AT+QLWADDOBJ=19,0,1,"0"\r
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+QLWADDOBJ=19,0,1,\"0\"\r"));
    if (ret < 0) {
        return ret;
    }
    //AT+QLWADDOBJ=19,1,1,"0"\r
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+QLWADDOBJ=19,1,1,\"0\"\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    //AT+QLWCFG="dataformat",1,1\r
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+QLWCFG=\"dataformat\",1,1\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    //AT+QLWOPEN=0\r
    xQueueReset(env_net.qinfo); //clear
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+QLWOPEN=0\r"));
    if (ret < 0) {
        return ret;
    }
    //The maximum timeout for connect operation is about 62s,refer to AT+QLWOPEN
    //CONNECT OK
    ret = NET_ERR_UNKOWN;
    for (len = 0; len < 62; len++) {
        NET_INF("connecting%02d...", len);
        if (xQueueReceive(env_net.qinfo, &msg_at, 1000) == pdPASS) {
            ret = NET_ERR_OK;
            break;
        }
    }
    if (ret != NET_ERR_OK) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    if (msg_at.info != AT_INFO_CONNECT_OK) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    //+QLWOBSERVE: 0,19,0,0
    if (xQueueReceive(env_net.qinfo, &msg_at, 10000) != pdPASS) {
        NET_ERR("failed to be observed");
        return NET_ERR_UNKOWN;
    }
    if (msg_at.info != AT_INFO_LWOBSERVE_REQUEST) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    return NET_ERR_OK;
}
//China Telecom send
NET_ERR_CODE drv_bc26_ct_send(uint8_t *pdata, uint32_t len) {
    uint8_t *pbuf;
    int32_t pbuf_len;
    NET_ERR_CODE ret;
    if (pdata == NULL) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    pbuf = pvPortMalloc(BASE16_ENCODE_LEN(BASE64_ENCODE_LEN(len)) + 64);
    if (pbuf == NULL) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    pbuf_len = snprintf((char *)pbuf, 64, "AT+QLWDATASEND=19,0,0,%d,00%02x%02x", BASE64_ENCODE_LEN(len) + 3, BASE64_ENCODE_LEN(len) >> 8,BASE64_ENCODE_LEN(len) & 0xFFu);
    if (pbuf_len < 0) {
        NET_ERR("");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }
    len = base16_base64_encode(pdata, len, pbuf + pbuf_len, BASE16_ENCODE_LEN(BASE64_ENCODE_LEN(len)));
    if (len == 0) {
        NET_ERR("failed to encode by base16_base64");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }
    pbuf_len += len;
    memcpy(pbuf + pbuf_len, CSTRING(",0x0000\r"));
    pbuf_len += sizeof(",0x0000\r") - 1;

    ret = drv_net_write_bytes_raw(500, 1, pbuf, pbuf_len);

    if (ret < 0) {
        NET_ERR("");
        vPortFree(pbuf);
        return ret;
    }

    vPortFree(pbuf);
    return NET_ERR_OK;
}

NET_ERR_CODE drv_bc26_upgrade_send(uint8_t *pdata, uint32_t len) {
    uint8_t *pbuf;
    int32_t pbuf_len;
    NET_ERR_CODE ret;
    if (pdata == NULL) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    pbuf = pvPortMalloc(BASE16_ENCODE_LEN(len) + 64);
    if (pbuf == NULL) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    pbuf_len = snprintf((char *)pbuf, 64, "AT+QLWDATASEND=19,0,0,%d,", len);
    if (pbuf_len < 0) {
        NET_ERR("");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }
	len = base16_encode(pdata,len,pbuf + pbuf_len,BASE16_ENCODE_LEN(len));
    if (len == 0) {
        NET_ERR("failed to encode by base16");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }
    pbuf_len += len;
    memcpy(pbuf + pbuf_len, CSTRING(",0x0000\r"));
    pbuf_len += sizeof(",0x0000\r") - 1;

    ret = drv_net_write_bytes_raw(500, 1, pbuf, pbuf_len);

    if (ret < 0) {
        NET_ERR("");
        vPortFree(pbuf);
        return ret;
    }

    vPortFree(pbuf);
    return NET_ERR_OK;
}

//China Telecom disconnect
NET_ERR_CODE drv_bc26_ct_disconnect(void) {
    NET_ERR_CODE ret;
    MSG_AT msg_at;
    xQueueReset(env_net.qinfo); //clear
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+QLWCLOSE\r"));
    if (ret < 0) {
        return ret;
    }
    if (xQueueReceive(env_net.qinfo, &msg_at, 5000) != pdPASS) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    if (msg_at.info != AT_INFO_CLOSE_OK) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    ret = drv_net_write_bytes_raw(5000, 1, TSTRING(uint8_t *,"AT+QLWDEL\r"));
    if (ret < 0) {
        return ret;
    }
    return NET_ERR_OK;
}

//China Mobile connect
NET_ERR_CODE drv_net_cm_connect(char *pstr_ip, char *pstr_port, uint32_t fifo_size, uint32_t flags) {
    char pbuf[64];
    int32_t len;
    NET_ERR_CODE ret;
    MSG_AT msg_at;
    uint32_t i;
    //init fifo
    ret = drv_net_fifo_init(&(env_net.pconns[0].fifo), fifo_size);
    if (ret < 0) {
        NET_ERR("unknown");
        return ret;
    }
    //AT+MIPLCONFIG=<mode>,<recv_data_format>[,<bsMode>,<ip>,<port>]
    //AT+MIPLCONFIG=0,1,1,"183.230.40.39",5683
    //len = snprintf(pbuf,sizeof(pbuf),"AT+MIPLCONFIG=0,1\r");
    if ((pstr_ip != NULL) && (pstr_port != NULL)) {
        len = snprintf(pbuf, sizeof(pbuf), "AT+MIPLCONFIG=0,0,1,\"%s\",%s\r", pstr_ip, pstr_port);
        if (len < 0) {
            NET_ERR("format");
            return NET_ERR_UNKOWN;
        }
        ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
        if (ret < 0) {
            NET_ERR("");
            return ret;
        }
    }

    xQueueReset(env_net.qinfo); //clear
    if (flags & CM_FLAG_REG_CODE) {
        ret = drv_net_write_bytes_raw(3000, 1, TSTRING(uint8_t * , "AT+MIPLCREATE=49,130031F10003F2002304001100000000000000123138332E3233302E34302E34303A35363833000131F30008C000000000,0,49,0\r"));
    } else {
        ret = drv_net_write_bytes_raw(3000, 1, TSTRING(uint8_t * , "AT+MIPLCREATE\r"));
    }
    if (ret < 0) {
        return ret;
    }
    if (xQueueReceive(env_net.qinfo, &msg_at, 5000) != pdPASS) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    if (msg_at.info != AT_INFO_CSI_OK) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }

    //AT+MIPLADDOBJ=<ref>,<objId>,<insCount>,<insBitmap>,<attrCount>,<actCount>
    //AT+MIPLADDOBJ=0,3348,2,"11",1,2
    len = snprintf(pbuf,sizeof(pbuf),"AT+MIPLADDOBJ=0,%d,2,\"11\",1,2\r",CM_OBJ_ID);
    if (len < 0) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }

    ret = drv_net_write_bytes_raw(500,1,(uint8_t *)pbuf,len);
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }

    xQueueReset(env_net.qinfo); //clear
    if (flags & CM_FLAG_LIFETIME) {
        ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t * , "AT+MIPLOPEN=0,86400,60\r")); //24hours
    } else {
        ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t * , "AT+MIPLOPEN=0,86400\r")); //24hours
    }

    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    //register
    ret = NET_ERR_UNKOWN;
    for (i = 0; i < 30; i++) {
        NET_INF("wait for register to finish...");
        if (xQueueReceive(env_net.qinfo, &msg_at, 1000) == pdPASS) {
            if (msg_at.info == AT_INFO_REG_SUCCESS) {
                ret = NET_ERR_OK;
                NET_INF("registered successfully");
                break;
            } else if (msg_at.info == AT_INFO_REG_FAILED) {
                break;
            } else {
                NET_WAR("invalid info %08x", msg_at.info);
            }
        }
    }
    if (ret != NET_ERR_OK) {
        NET_ERR("registered to onenet timeout");
        return ret;
    }
    //observer & discover
    ret = NET_ERR_UNKOWN;
    for (i = 0; i < 25; i++) {
        NET_INF("wait for discovery to finish...");
        if (xQueueReceive(env_net.qinfo, &msg_at, 1000) == pdPASS) {
            if (msg_at.info == AT_INFO_MIPLDISCOVER_OK) {
                ret = NET_ERR_OK;
                NET_INF("discovered successfully");
                break;
            } else if (msg_at.info == AT_INFO_MIPLDISCOVER_ERROR) {
                break;
            } else {
                NET_WAR("invalid info %08x", msg_at.info);
            }
        }
    }
    if (ret != NET_ERR_OK) {
        NET_ERR("registered to onenet timeout");
        return ret;
    }
    return NET_ERR_OK;
}

NET_ERR_CODE drv_bc26_cm_connect(char *pstr_ip, char *pstr_port, uint32_t fifo_size) {
    return drv_net_cm_connect(pstr_ip, pstr_port, fifo_size, 0);
}

#if 1
NET_ERR_CODE drv_net_cm_send(uint8_t *pdata, uint32_t len, uint32_t flags) {
    uint8_t *pbuf;
    int32_t pbuf_len;
    NET_ERR_CODE ret;

    if (pdata == NULL) {
        NET_ERR("null pointer");
        return NET_ERR_UNKOWN;
    }

    pbuf = pvPortMalloc(BASE64_ENCODE_LEN(len) + 64);
    if (pbuf == NULL) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    //AT+MIPLNOTIFY=<ref>,<msgId>,<objId>,<insId>,<resId>,<valueType>,<len>,<value>,<index>,<flag>[,<ackid>]
    //AT+MIPLNOTIFY=0,120258,3348,0,5750,1,5,"hello",0,0\r
    //<valueType> is 2,that mean opaque,
    if (flags & CM_FLAG_WITH_QUOTATION) {
        pbuf_len = snprintf((char *)pbuf, 64, "AT+MIPLNOTIFY=0,%d,%d,%d,%s,1,%d,\"", env_net.cm_up_msg_id, CM_OBJ_ID, CM_INS_ID_UP, CM_RES_ID_STR, BASE64_ENCODE_LEN(len) + 2);
    } else {
        pbuf_len = snprintf((char *)pbuf, 64, "AT+MIPLNOTIFY=0,%d,%d,%d,%s,1,%d,\"", env_net.cm_up_msg_id, CM_OBJ_ID, CM_INS_ID_UP, CM_RES_ID_STR, BASE64_ENCODE_LEN(len));
    }
    if (pbuf_len < 0) {
        NET_ERR("failed to format");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }
    len = base64_encode(pdata, len, pbuf + pbuf_len, BASE64_ENCODE_LEN(len));
    if (len == 0) {
        NET_ERR("failed to encode by base64");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }
    pbuf_len += len;
    memcpy(pbuf + pbuf_len, CSTRING("\",0,0\r"));
    pbuf_len += (sizeof("\",0,0\r") - 1);

    ret = drv_net_write_bytes_raw(500, 1, pbuf, pbuf_len);

    if (ret < 0) {
        NET_ERR("");
        vPortFree(pbuf);
        return ret;
    }

    vPortFree(pbuf);
    return NET_ERR_OK;
}
#else


NET_ERR_CODE drv_bc26_cm_send(uint8_t *pdata,uint32_t len){
    uint8_t *pbuf;
    int32_t pbuf_len;
    NET_ERR_CODE ret;

    if(pdata == NULL){
        NET_ERR("null pointer");
        return NET_ERR_UNKOWN;
    }

    pbuf = pvPortMalloc((len << 1) + 64);
    if(pbuf == NULL){
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    //AT+MIPLNOTIFY=<ref>,<msgId>,<objId>,<insId>,<resId>,<valueType>,<len>,<value>,<index>,<flag>[,<ackid>]
    //AT+MIPLNOTIFY=0,120258,3348,0,5750,1,5,"hello",0,0\r
    //<valueType> is 2,that mean opaque,
    pbuf_len = snprintf((char *)pbuf,64,"AT+MIPLNOTIFY=0,%d,%d,%d,%s,2,%d,",env_net.cm_up_msg_id,CM_OBJ_ID,CM_INS_ID_UP,CM_RES_ID_STR,len);
    if(pbuf_len < 0){
        NET_ERR("failed to format");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }
    bin_to_hstr(pbuf + pbuf_len,pdata,len);
    pbuf_len += (len << 1);
    memcpy(pbuf + pbuf_len,CSTRING(",0,0\r"));
    pbuf_len += (sizeof(",0,0\r") - 1);

    ret = drv_net_write_bytes_raw(500,1,pbuf,pbuf_len);

    if(ret < 0){
        NET_ERR("");
        vPortFree(pbuf);
        return ret;
    }

    vPortFree(pbuf);
    return NET_ERR_OK;
}
#endif
NET_ERR_CODE drv_bc26_cm_send(uint8_t *pdata, uint32_t len) {
    return drv_net_cm_send(pdata, len, 0);
}

NET_ERR_CODE drv_net_cm_disconnect(void) {
    uint32_t i;
    char pbuf[64];
    int32_t len;
    NET_ERR_CODE ret;
    MSG_AT msg_at;
    //AT+MIPLDELOBJ=<ref>,<objId>
    //AT+MIPLDELOBJ=0,3348
    len = snprintf(pbuf, sizeof(pbuf), "AT+MIPLDELOBJ=0,%d\r", CM_OBJ_ID);
    if (len <= 0) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }

    ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }

    //AT+MIPLCLOSE=<ref>
    //AT+MIPLCLOSE=0
    xQueueReset(env_net.qinfo);
    ret = drv_net_write_bytes_raw(10000, 1, TSTRING(uint8_t *,"AT+MIPLCLOSE=0\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }

    ret = NET_ERR_UNKOWN;
    for (i = 0; i < 20; i++) {
        NET_INF("wait for being deregistered to finish");
        if (xQueueReceive(env_net.qinfo, &msg_at, 1000) == pdPASS) {
            if (msg_at.info == AT_INFO_DEREG_DONE) {
                ret = NET_ERR_OK;
                break;
            } else {
                NET_WAR("invalid inf");
            }
        }
    }

    if (ret != NET_ERR_OK) {
        return NET_ERR_UNKOWN;
    }

    //AT+MIPLDELETE=<ref>
    //AT+MIPLDELETE=0
    ret = drv_net_write_bytes_raw(6000, 1, TSTRING(uint8_t *,"AT+MIPLDELETE=0\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    return NET_ERR_OK;
}
NET_ERR_CODE drv_bc26_cm_disconnect(void) {
    return drv_net_cm_disconnect();
}

NET_ERR_CODE drv_bc26_socket_connect(int32_t socket, DRV_NET_SOCKET_TYPE service_type, char *pstr_ip, char *pstr_port, uint32_t fifo_size) {
    char pbuf[64];
    int32_t len;
    MSG_AT msg_at;
    NET_ERR_CODE ret;
    uint32_t i;
    if (!BETWEEN10(0, socket, DRV_NET_MAX_NUM_OF_CONNECTIONS)) {
        NET_ERR("invalid socket");
        return NET_ERR_UNKOWN;
    }
    if ((pstr_ip == NULL) || (pstr_port == NULL)) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    //init fifo
    ret = drv_net_fifo_init(&(env_net.pconns[socket].fifo), fifo_size);
    if (ret < 0) {
        NET_ERR("unknown");
        return ret;
    }

    //AT+QIOPEN=<contextID>,<connectID>,<service_type>,<IP_address>/<domain_name>,<remote_port>[,<local_port>[,<access_mode>]
    if (service_type == DRV_NET_SOCKET_UDP) {
        len = snprintf(pbuf, sizeof(pbuf), "AT+QIOPEN=%d,%d,\"UDP\",\"%s\",%s,0,1\r", env_net.cid, socket, pstr_ip, pstr_port);
    } else {
        len = snprintf(pbuf, sizeof(pbuf), "AT+QIOPEN=%d,%d,\"TCP\",\"%s\",%s,0,1\r", env_net.cid, socket, pstr_ip, pstr_port);
    }

    if (len < 0) {
        NET_ERR("format");
        return NET_ERR_UNKOWN;
    }


    xQueueReset(env_net.qinfo); //clear
    ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }

    ret = NET_ERR_UNKOWN;
    for (i = 0; i < 30; i++) {
        NET_INF("wait for connection%d...", i);
        if (xQueueReceive(env_net.qinfo, &msg_at, 1000) == pdPASS) {
            if ((msg_at.info == AT_INFO_SOCKET_OPEN_OK) &&
                (msg_at.value == socket)) {
                NET_INF("open socket %d successfully", socket);
                ret = NET_ERR_OK;
                break;
            } else if ((msg_at.info == AT_INFO_SOCKET_OPEN_ERROR) &&
                       (msg_at.value == socket)) {
                NET_ERR("failed to open socket %d", socket);
                ret = NET_ERR_UNKOWN;
                break;
            } else {
                NET_WAR("invalid info %08x", msg_at.info);
            }
        }
    }

    return ret;
}


NET_ERR_CODE drv_bc26_socket_send(int32_t socket, uint8_t *pdata, uint32_t len) {
    uint8_t *pbuf;
    int32_t pbuf_len;
    NET_ERR_CODE ret;
    MSG_AT msg_at;
    if (pdata == NULL) {
        NET_ERR("null pointer");
        return NET_ERR_UNKOWN;
    }
    pbuf = pvPortMalloc((len << 1) + 64);
    if (pbuf == NULL) {
        NET_ERR("failed to malloc send buffer");
        return NET_ERR_UNKOWN;
    }

    pbuf_len = snprintf((char *)pbuf, 64, "AT+QISENDEX=%d,%d,", socket, len);

    if (pbuf_len < 0) {
        NET_ERR("format");
        vPortFree(pbuf);
        return NET_ERR_UNKOWN;
    }

    bin_to_hstr(pbuf + pbuf_len, pdata, len);
    pbuf_len += (len << 1);
    memcpy(pbuf + pbuf_len, CSTRING("\r"));
    pbuf_len += (sizeof("\r") - 1);


    xQueueReset(env_net.qinfo);
    ret = drv_net_write_bytes_raw(500, 1, pbuf, pbuf_len);

    if (ret < 0) {
        NET_ERR("failed to send");
        vPortFree(pbuf);
        return ret;
    }


    if (xQueueReceive(env_net.qinfo, &msg_at, 2000) == pdPASS) {
        if (msg_at.info != AT_INFO_SOCKET_SEND_OK) {
            NET_ERR("send failed %08x", msg_at.info);
            vPortFree(pbuf);
            return NET_ERR_UNKOWN;
        }
    }
    vPortFree(pbuf);
    return NET_ERR_OK;
}


NET_ERR_CODE drv_bc26_socket_disconnect(int32_t socket) {
    char pbuf[64];
    int32_t len;
    NET_ERR_CODE ret;
    uint32_t i;
    MSG_AT msg_at;
    if (!BETWEEN10(0, socket, DRV_NET_MAX_NUM_OF_CONNECTIONS)) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    len = snprintf(pbuf, sizeof(pbuf), "AT+QICLOSE=%d\r", socket);
    if (len < 0) {
        NET_ERR("format");
        return NET_ERR_UNKOWN;
    }
    ret = drv_net_write_bytes_raw(500, 1, (uint8_t *)pbuf, len);
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }

    ret = NET_ERR_UNKOWN;
    for (i = 0; i < 5; i++) {
        if (xQueueReceive(env_net.qinfo, &msg_at, 1000) == pdPASS) {
            if (msg_at.info == AT_INFO_CLOSE_OK) {
                ret  = NET_ERR_OK;
                NET_INF("closed socket %d successfully", socket);
                break;
            } else {
                NET_WAR("invalid info %08x", msg_at.info);
            }
        }
    }

    if (ret != NET_ERR_OK) {
        return ret;
    }
    return NET_ERR_OK;
}



NET_ERR_CODE drv_bc26_try_to_get_ip(void) {
    NET_ERR_CODE ret;
    MSG_AT msg_at;
    uint32_t i;
//    if(env_net.state != NET_STATE_POWER_ON){
//        NET_ERR("invalid state");
//        return NET_ERR_STATE;
//    }

    ret = drv_net_write_bytes_raw(500, 4, TSTRING(uint8_t *,"AT\r"));
    if (ret < 0) {
        NET_ERR("module might be broken");
        return ret;
    }
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"ATE0\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    xQueueReset(env_net.qinfo); //clear
    ret = drv_net_write_bytes_raw(3000, 1, TSTRING(uint8_t *,"AT+CPIN?\r"));
    if (ret < 0) {
        if (ret == NET_ERR_AT) {
            NET_ERR("no sim card");
            return NET_ERR_NO_CARD;
        } else {
            return ret;
        }
    }
	env_net.sim_status = 1;
    if (xQueueReceive(env_net.qinfo, &msg_at, 1000) != pdPASS) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    if (msg_at.info != AT_INFO_CARD_READY) {
        NET_ERR("sim card is not ready");
        return NET_ERR_UNKOWN;
    }

    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"ATI\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }

    //get imei
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+CGSN=1\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }

    //get imsi
    ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+CIMI\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }


	ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+QCCID\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
//    ret = drv_net_write_bytes_raw(500,1,TSTRING(uint8_t *,"AT+QSM=LOCK\r"));
//    if(ret < 0){
//        NET_ERR("");
//        return ret;
//    }
//    ret = drv_net_write_bytes_raw(500,1,TSTRING(uint8_t *,"AT+CPSMS=0\r"));
//    if(ret < 0){
//        NET_ERR("");
//        return ret;
//    }

    xQueueReset(env_net.qinfo); //clear
    ret = drv_net_write_bytes_raw(500, 4, TSTRING(uint8_t *,"AT+CGATT?\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    if (xQueueReceive(env_net.qinfo, &msg_at, 200) != pdPASS) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
//  if(msg_at.info == AT_INFO_CGATT0){
//        ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+QGACT=1,1,\"ctnb\"\r"));
//      if(env_net.carrier == DRV_NET_CARRIER_CM){
//          ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+QGACT=1,1,\"CMNBIOT\"\r"));
//          if(ret < 0){
//              NET_ERR("");
//              return ret;
//          }
//      }
//  }
    ret = NET_ERR_UNKOWN;
    for (i = 0; i < 30; i++) {
        NET_INF("try to get ip%02d...", 50 - i);
        drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CSQ\r"));
        xQueueReset(env_net.qinfo); //clear
        drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CGPADDR\r"));
        if (xQueueReceive(env_net.qinfo, &msg_at, 1000) == pdPASS) {
            if (msg_at.info == AT_INFO_CGPADDR) {
                ret = NET_ERR_OK;
                break;
            } else {
                NET_WAR("unexpected msg%08x", msg_at.info);
            }
        }
    }
    if (ret < 0) {
        NET_ERR("failed to get ip");
        return ret;
    }
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+QATWAKEUP=1\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+QNBIOTEVENT=1,1\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CEREG=5\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+QICFG=\"viewmode\",1 \r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+QICFG=\"dataformat\",1,1\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    //T3324:20s
//    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CPSMS=1,,,\"01000100\",\"00000000\"\r"));
//    if (ret < 0) {
//        NET_ERR("");
//        return ret;
//    }
	ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CPSMS=0,,,\"01000100\",\"00000000\"\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    //request apn name
    ret =  drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CGDCONT?\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
	ret = drv_net_write_bytes_raw(500, 1, TSTRING(uint8_t *,"AT+SM=LOCK\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    return NET_ERR_OK;
}

NET_ERR_CODE drv_bc26_try_to_sleep(void) {
    NET_ERR_CODE ret;
    MSG_AT msg_at;
    uint32_t i;
    ret = drv_net_write_bytes_raw(1000, 1, TSTRING(uint8_t *,"AT+SM=UNLOCK\r"));
    if (ret < 0) {
        NET_ERR("");
        return NET_ERR_UNKOWN;
    }
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CPSMS=1,,,\"01000100\",\"00000000\"\r"));
    if (ret < 0) {
        NET_ERR("");
        return ret;
    }
    for (i = 60; i > 0; i--) {
        xQueueReset(env_net.qinfo);
        ret = drv_net_write_bytes_raw(1000, 1, TSTRING(uint8_t * , "AT+CSCON?\r"));
        if (ret < 0) {
            NET_ERR("");
            return NET_ERR_UNKOWN;
        }
        if (xQueueReceive(env_net.qinfo, &msg_at, 200) == pdPASS) {
            if (msg_at.info == AT_INFO_CSCON) {
                NET_INF("moduel state %d", msg_at.value);
                if (msg_at.value == 0) {
                    break;
                }
            } else {
                NET_WAR("unexpected msg %08x", msg_at.info);
            }
            vTaskDelay(1000);
        } else if (i == 1) {
            NET_ERR("wait for idle state timeout");
            drv_net_write_bytes_raw(1000, 1, TSTRING(uint8_t * , "AT+SM=LOCK\r"));
			drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CPSMS=0,,,\"01000100\",\"00000000\"\r"));
            return NET_ERR_UNKOWN;
        }
    }
    for (i = 15; i > 0; i--) {
        NET_INF("wait for sleeping%d...", i);
        vTaskDelay(1000);
    }
    if (drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT\r")) < 0) {
        return NET_ERR_OK;
    } else {
        drv_net_write_bytes_raw(1000, 1, TSTRING(uint8_t * , "AT+SM=LOCK\r"));
		drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CPSMS=0,,,\"01000100\",\"00000000\"\r"));
        return NET_ERR_UNKOWN;
    }
}

NET_ERR_CODE drv_bc26_cmd_sq_get(uint32_t *psq) {
    NET_ERR_CODE ret;
    ret = drv_net_write_bytes_raw(1000, 1, TSTRING(uint8_t * , "AT+CSQ\r"));
    if (ret < 0) {
        *psq = 0;
        return ret;
    }
    *psq = env_net.sq;
    return NET_ERR_OK;
}

NET_ERR_CODE drv_bc26_cell_inf_get(CELL_INF *pcell_inf) {
    NET_ERR_CODE ret;
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+QENG=0\r"));
    if (ret < 0) {
        return NET_ERR_UNKOWN;
    }
    memcpy(pcell_inf, &env_net.cell_inf,sizeof(CELL_INF));
    return NET_ERR_OK;
}

NET_ERR_CODE drv_bc26_date_info_get(NET_DATE_T *t) {
    NET_ERR_CODE ret;
    ret = drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CCLK?\r"));
    if (ret < 0) {
        return NET_ERR_UNKOWN;
    }
	memcpy(t, &env_net.date_t,sizeof(NET_DATE_T));
    return NET_ERR_OK;
}

NET_ERR_CODE drv_bc26_executor(NET_CMD_CODE cmd, void *pdata) {
    if (cmd == NET_CMD_SQ_GET) {
        return drv_bc26_cmd_sq_get((uint32_t *)pdata);
    } else if (cmd == NET_CMD_CT_ID_TYPE_GET){
        *((NET_CT_ID_TYPE *)pdata) = NET_CT_ID_IMEI;
        return NET_ERR_OK;
    } else if (cmd == NET_CMD_CELL_INF_GET) {
        return drv_bc26_cell_inf_get((CELL_INF *)pdata);
    } else if (cmd == NET_CMD_CCLK_TIME_GET) { 
		return drv_bc26_date_info_get((NET_DATE_T *)pdata);
	} else {
        return NET_ERR_UNKOWN;
    }
}

NET_ERR_CODE drv_bc26_try_to_wake_up(void) {
    NET_ERR_CODE ret;
    NET_INF("wake up...");
    drv_net_power_wake_up();
    vTaskDelay(300);
    ret = drv_net_write_bytes_raw(500, 4, TSTRING(uint8_t *,"AT\r"));
    if (ret < 0) {
        return ret;
    }
	drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+CPSMS=0,,,\"01000100\",\"00000000\"\r"));
    return drv_net_write_bytes_raw(1000,1,TSTRING(uint8_t *,"AT+SM=LOCK\r"));
}


NET_ERR_CODE drv_bc26_power_set(NET_POWER_CONTROL net_power){
    if (net_power == NET_POWER_ON) {
        env_net.pat_handlers = drv_bc26_at_handlers;
        return drv_bc26_try_to_get_ip();
    } else if (net_power == NET_POWER_OFF) {
        drv_net_power_off();
        return NET_ERR_OK;
    } else if (net_power == NET_POWER_SLEEP) {
        return drv_bc26_try_to_sleep();
    } else if (net_power == NET_POWER_WAKE) {
        return drv_bc26_try_to_wake_up();
    } else {
        NET_ERR("invalid power state");
        return NET_ERR_UNKOWN;
    }
}



const DRV_NET_INTERFACE drv_bc26_interface = {
    .pf_power_set = drv_bc26_power_set,
    .pf_executor = drv_bc26_executor,
    //ct
    .pf_ct_connect = drv_bc26_ct_connect,
    .pf_ct_send = drv_bc26_ct_send,
    .pf_ct_disconnect = drv_bc26_ct_disconnect,
    //cm
    .pf_cm_connect = drv_bc26_cm_connect,
    .pf_cm_send = drv_bc26_cm_send,
    .pf_cm_disconnect = drv_bc26_cm_disconnect,
    //socket
    .pf_socket_connect = drv_bc26_socket_connect,
    .pf_socket_send = drv_bc26_socket_send,
    .pf_socket_disconnect = drv_bc26_socket_disconnect
};

